package org.jsets.fastboot.quartz.component;

import java.util.Map;
import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.JobListener;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerListener;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.TriggerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 抽象的JOB配置，供使用者继承
 * 
 * @author wangjie (https://github.com/wj596)
 * @date 2016年6月31日
 *
 */
public class QuartzService {

	public static final Logger LOGGER = LoggerFactory.getLogger(QuartzService.class);

	@Autowired
	private Scheduler scheduler;

	/**
	 * 调度任务
	 * 
	 * @param jobClass 任务定义类(必须实现Job接口)
	 * @param cron cron表达式
	 */
	public void scheduleJob(Class<? extends Job> jobClass, String cron) {
		this.scheduleJob(jobClass, jobClass.getName(), null, cron);
	}

	/**
	 * 调度任务
	 * 
	 * @param jobClass 任务定义类(必须实现Job接口)
	 * @param jobKey 任务的KEY
	 * @param cron cron表达式
	 */
	public void scheduleJob(Class<? extends Job> jobClass, String jobKey, String cron) {
		this.scheduleJob(jobClass, jobKey, null, cron);
	}
	
	/**
	 * 调度任务
	 * 
	 * @param jobClass 任务定义类(必须实现Job接口)
	 * @param jobDatas 传递到JobExecutionContext中的数据
	 * @param cron cron表达式
	 */
	public boolean scheduleJob(Class<? extends Job> jobClass, Map<String, Object> jobDatas, String cron) {
		boolean exist = false;
		String jobKey = jobClass.getName();
		try {
			exist = this.scheduler.checkExists(new JobKey(jobKey));
		} catch (SchedulerException e) {
			LOGGER.warn(e.getMessage(), e);
		}
		
		if(exist) {
			LOGGER.warn("Job[{}] already exists", jobKey);
			return false;
		}
		
		JobDataMap jobDataMap = new JobDataMap();
		if (null != jobDatas) {
			jobDataMap.putAll(jobDatas);
		}
		JobDetail jobDetail = JobBuilder
				.newJob(jobClass)
				.withIdentity(jobKey)
				.usingJobData(jobDataMap)
				.build();
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
		CronTrigger trigger = TriggerBuilder
				.newTrigger()
				.withIdentity(jobKey)
				.withSchedule(scheduleBuilder)
				.build();
		try {
			this.scheduler.scheduleJob(jobDetail, trigger);
			return true;
		} catch (SchedulerException e) {
			LOGGER.error("scheduleJob failed. throw ex:", e);
		}
		return false;
	}

	/**
	 * 调度任务
	 * 
	 * @param jobClass 任务定义类(必须实现Job接口)
	 * @param jobKey 任务的KEY
	 * @param jobDatas 传递到JobExecutionContext中的数据
	 * @param cron cron表达式
	 */
	public void scheduleJob(Class<? extends Job> jobClass, String jobKey, Map<String, Object> jobDatas, String cron) {
		boolean exist = false;
		try {
			exist = this.scheduler.checkExists(new JobKey(jobKey));
		} catch (SchedulerException e) {
			LOGGER.warn(e.getMessage(), e);
		}
		if(exist) {
			throw new RuntimeException("任务Job ["+jobKey+"]已存在");
		}
		
		JobDataMap jobDataMap = new JobDataMap();
		if (null != jobDatas) {
			jobDataMap.putAll(jobDatas);
		}
		JobDetail jobDetail = JobBuilder
				.newJob(jobClass)
				.withIdentity(jobKey)
				.usingJobData(jobDataMap)
				.build();
		CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
		CronTrigger trigger = TriggerBuilder
				.newTrigger()
				.withIdentity(jobKey)
				.withSchedule(scheduleBuilder)
				.build();
		try {
			this.scheduler.scheduleJob(jobDetail, trigger);
		} catch (SchedulerException e) {
			LOGGER.error(e.getMessage(), e);
			throw new RuntimeException("调度任务["+jobKey+"]失败：", e);
		}
	}
	
	/**
	 * 触发任务
	 * @param jobKey 任务的KEY
	 * @return 是否触发成功
	 */
	public boolean triggerJob(String jobKey) {
		try {
			this.scheduler.triggerJob(new JobKey(jobKey));
			return true;
		} catch (Exception e) {
			LOGGER.error("triggerJob failed. throw ex:", e);
		}
		return false;
	}

	/**
	 * 删除任务
	 * @param key 任务的KEY
	 * @return 是否删除成功
	 */
	public void removeTask(String key) {
		try {
			this.scheduler.pauseTrigger(new TriggerKey(key));
			this.scheduler.unscheduleJob(new TriggerKey(key));
			this.scheduler.deleteJob(new JobKey(key));
		} catch (SchedulerException e) {
			LOGGER.error("removeJob failed. throw ex:", e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	/**
	 * 暂停任务
	 * @param jobKey 任务的KEY
	 * @return 是否暂停成功
	 */
	public void pauseJob(String jobKey) {
		try {
			this.scheduler.pauseJob(new JobKey(jobKey));
		} catch (SchedulerException e) {
			LOGGER.error("pauseJob failed. throw ex:", e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	/**
	 * 重启任务
	 * @param jobKey 任务的KEY
	 * @return 是否重启成功
	 */
	public void resumeJob(String jobKey) {
		try {
			this.scheduler.resumeJob(new JobKey(jobKey));
		} catch (Exception e) {
			LOGGER.error("resumeJob failed. throw ex:", e);
		}
	}
	
	/**
	 * 添加任务监听
	 * @param jobListener 任务监听器
	 */
	public void addJobListener(JobListener jobListener) {
		try {
			this.scheduler.getListenerManager().addJobListener(jobListener);
		} catch (SchedulerException e) {
			LOGGER.error("addJobListener failed. throw ex:", e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	/**
	 * 添加调度监听
	 * @param schedulerListener 调度监听器
	 */
	public void addSchedulerListener(SchedulerListener schedulerListener) {
		try {
			this.scheduler.getListenerManager().addSchedulerListener(schedulerListener);
		} catch (SchedulerException e) {
			LOGGER.error("addSchedulerListener failed. throw ex:", e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	/**
	 * 添加触发监听
	 * @param triggerListener 触发监听器
	 */
	public void addTriggerListener(TriggerListener triggerListener) {
		try {
			this.scheduler.getListenerManager().addTriggerListener(triggerListener);
		} catch (SchedulerException e) {
			LOGGER.error("triggerListener failed. throw ex:", e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	

	/**
	 * 是否存在任务
	 * @param jobKey 任务的KEY
	 * @return 任务详细
	 */
	public boolean isExistsJob(String key) {
		try {
			return this.scheduler.checkExists(new JobKey(key));
		} catch (SchedulerException e) {
			LOGGER.error(e.getMessage(), e);
		}
		return false;
	}
	
	/**
	 * 获取任务详细
	 * @param jobKey 任务的KEY
	 * @return 任务详细
	 */
	public JobDetail getJobDetail(String key) {
		try {
			return this.scheduler.getJobDetail(new JobKey(key));
		} catch (SchedulerException e) {
			LOGGER.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	
	public Trigger getTrigger(String key) {
		try {
			return this.scheduler.getTrigger(new TriggerKey(key));
		} catch (SchedulerException e) {
			LOGGER.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	public CronTrigger getCronTrigger(String key) {
		try {
			Trigger trigger = this.scheduler.getTrigger(new TriggerKey(key));
			return (CronTrigger) trigger;
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}
	
	public TriggerState getTriggerState(String key) {
		try {
			TriggerState triggerState = this.scheduler.getTriggerState(new TriggerKey(key));
			return triggerState;
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	/**
	 * 验证cron表达式
	 * @param cronExpression cron表达式
	 * @return 是否验证成功
	 */
	public boolean isValidExpression(final String cronExpression) {
		return CronExpression.isValidExpression(cronExpression);
	}

	/**
	 * 获取Scheduler
	 * @return Scheduler
	 */
	public Scheduler getScheduler() {
		return scheduler;
	}
}